import wx
import os
from pyeasyaccept.gui.ChooseTestScript import ChooseTestScript
from pyeasyaccept.commom.Configuration import Configuration
from pyeasyaccept.gui.ErrorMsg import ErrorMsg
from pyeasyaccept.gui.ScriptToSave import ScriptToSave

class ChooseScriptsPanel(wx.Panel):
    """ 
    It is a panel that allows the user to select and choose the test scripts which will be run. 
    
    @author: Danilo Torres
    """   
    
    INITIAL_BROWSE_ID = 1
    MAX_BROWSE_ID = 100
    
    INITIAL_REMOVE_ID = 101
    MAX_REMOVE_ID = 200
    
    INITIAL_CHECK_BOX_ID = 301
    
    ADD_SCRIPT_TEST = 1000
    
    lastFolderBrowsed = None
    
    def __init__(self, parent, id):      
        """
        Initializes the panel by adding one empty test script line.
        @param parent: the parent of this panel
        @param id: the panel ID
        """  
        wx.Panel.__init__(self, parent, id, size=wx.Size(500, 300))
        self.gridBagSizer = wx.GridBagSizer(9, 9)

        self.emptySpace = wx.StaticText(self, -1, '')
        self.testScriptsLabel = wx.StaticText(self, -1, 'Test Scripts')
         
        self.gridBagSizer.Add(self.emptySpace, (0,0), wx.DefaultSpan, wx.ALIGN_LEFT)        
        self.gridBagSizer.Add(self.testScriptsLabel, (0,1), (1,10), wx.ALIGN_LEFT)
        
        self.resetLastInsertedRow()
        self.resetLastScriptTestID()
        self.idToScriptTest = {}
        
        self.addScriptLine()
            
        self.addTestScriptButton = wx.Button(self, self.ADD_SCRIPT_TEST, "Add a test script");
        self.gridBagSizer.Add(self.addTestScriptButton, (self.lastInsertedRow, 2), wx.DefaultSpan, wx.EXPAND)    
        self.Bind(wx.EVT_BUTTON, self.addScriptTestEvent, self.addTestScriptButton)
        
        self.SetAutoLayout(True)
        self.SetSizer(self.gridBagSizer)
        self.listeners = []
        
        
    def addScriptLine(self):
        """
        It adds an empty test script line.
        """
        textCtrlID = self.lastScriptTestID
        browseID = self.lastScriptTestID + self.INITIAL_BROWSE_ID - 1
        removeID = self.lastScriptTestID + self.INITIAL_REMOVE_ID - 1
        checkBoxID = self.lastScriptTestID + self.INITIAL_CHECK_BOX_ID - 1
        
        removeButton = wx.BitmapButton(self, removeID, wx.Bitmap(Configuration.INSTALL_DIR + Configuration.ICONS_LOCATION + Configuration.FILE_SEPARATOR + 'removeButton.png'))
        checkBox = wx.CheckBox(self, checkBoxID)
        chooseScriptLine = ChooseTestScript(self.lastScriptTestID, wx.StaticText(self, -1, ''), wx.TextCtrl(self, textCtrlID), wx.Button(self, browseID, 'Browse'), checkBox, removeButton)

        self.idToScriptTest[self.lastScriptTestID] = chooseScriptLine
        
        self.reAddScriptTest(self.gridBagSizer, chooseScriptLine)
        self.incrementLastScriptTestID()
        
        checkBox.Bind(wx.EVT_CHECKBOX, self.checkBoxClicked)
        chooseScriptLine.removeButton.Bind(wx.EVT_BUTTON, self.remove)
        self.Bind(wx.EVT_BUTTON, self.browse, chooseScriptLine.browseButton)

    def addListener(self, listener):
        self.listeners.append(listener)
        
    def addScriptTestEvent(self, event):
        """
        It receives an event from button: "Add a test script"
        @param event: an add script test button event 
        """
        if event.GetId() != self.ADD_SCRIPT_TEST:
            event.Skip()
            return
        self.addEmptyScriptTest()

    def checkBoxClicked(self, event):
        self.fireCheckBoxClicked()

    def addEmptyScriptTest(self):
        self.gridBagSizer.Remove(self.addTestScriptButton)
        self.addScriptLine()
        self.gridBagSizer.Add(self.addTestScriptButton, (self.lastInsertedRow, 2), wx.DefaultSpan, wx.EXPAND)
        self.gridBagSizer.Layout()
        self.Layout()
        self.fireScriptLineAdded()
        
    def addScriptTest(self, scriptTest, isSelected=True):
        self.addEmptyScriptTest()
        lastScriptID = self.lastScriptTestID - 1
        self.idToScriptTest[lastScriptID].setTestPath(scriptTest)
        self.idToScriptTest[lastScriptID].select(isSelected)        
        
    def browse(self, event):
        """
        It receives an event from browse button. It allows to choose a test script.
        @param event: a browse button event. 
        """
        eventID = event.GetId()
        if eventID > self.MAX_BROWSE_ID or eventID < self.INITIAL_BROWSE_ID:
            event.Skip()
            return
        path = None
        if self.lastFolderBrowsed != None:
            path = self.lastFolderBrowsed
        else:
            path =  Configuration.PATH_TO_BROWSE
        row = eventID - self.INITIAL_BROWSE_ID + 1
        scriptLine = self.idToScriptTest[eventID]
        
        dlg = wx.FileDialog(self, "Choose a script test", path, "", "*.txt", wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            scriptLine.textCtrl.SetValue(path)
            scriptLine.textCtrl.SetInsertionPointEnd()
            scriptLine.checkBox.SetValue(True)
            self.lastFolderBrowsed = path
            self.fireScriptTestAdded(path)
        dlg.Destroy()        
        
    def fireCheckBoxClicked(self):
        for listener in self.listeners:
            listener.notifyCheckBoxClicked()
        
    def fireScriptTestAdded(self, scriptTest):
        for listener in self.listeners:
            listener.notifyScriptTestAdded(scriptTest)

    def fireScriptRemoved(self):
        for listener in self.listeners:
            listener.notifyScriptRemoved()
            
    def fireScriptLineAdded(self):
        for listener in self.listeners:
            listener.notifyScriptLineAdded()
        
        
    def hasMinimumScriptTests(self):
        """
        @return: if has at least one test script selected. 
        """
        return len(self.idToScriptTest) == 1
    
    def remove(self, event):
        """
        It receives an event from remove button. It removes a test script line.
        @param event: a remove button event. 
        """        
        eventID = event.GetId()
            
        if eventID > self.MAX_REMOVE_ID or eventID < self.INITIAL_REMOVE_ID:
            event.Skip()
            return
    
        if self.hasMinimumScriptTests():
            ErrorMsg(self, ErrorMsg.MINIMUM_SCRIPT_TESTS)
            event.Skip()
            return

        rowToBeRemoved = eventID - self.INITIAL_REMOVE_ID + 1
        lineToBeRemoved = None
        moveValues = False
        for scriptLine in self.idToScriptTest.values():
            if rowToBeRemoved == scriptLine.id:
                moveValues = True

            if moveValues and scriptLine.id < len(self.idToScriptTest):
                next = scriptLine.id + 1
                nextValue = self.idToScriptTest.get(next).getTestPath()
                isNextSelected = self.idToScriptTest.get(next).isSelected()
                scriptLine.setTestPath(nextValue)
                scriptLine.select(isNextSelected) 
            
            elif moveValues:
                lineToBeRemoved = scriptLine
                self.removeScriptTest(scriptLine)
                
        self.gridBagSizer.Remove(self.addTestScriptButton)
        self.gridBagSizer.Add(self.addTestScriptButton, (self.lastInsertedRow,2), wx.DefaultSpan, wx.EXPAND)
        
        self.idToScriptTest.__delitem__(lineToBeRemoved.id)
        lineToBeRemoved.Destroy()
        self.gridBagSizer.Layout()
        self.GetParent().Layout()
        self.fireScriptRemoved()
        
    def resetLastInsertedRow(self):
        """
        It resets the last inserted row index to 1.
        """
        self.lastInsertedRow = 1
        
    def incrementLastInsertedRow(self):
        """
        It increments the last inserted row index.
        """
        self.lastInsertedRow += 1

    def decrementLastInsertedRow(self):
        """
        It decrements the last inserted row index.
        """
        self.lastInsertedRow -= 1
        
    def resetLastScriptTestID(self):
        """
        It resets the last script test ID to 1.
        """        
        self.lastScriptTestID = 1
        
    def incrementLastScriptTestID(self):
        """
        It increments the last script test ID.
        """        
        self.lastScriptTestID += 1
                
    def decrementLastScriptTestID(self):
        """
        It decrements the last script test ID.
        """        
        self.lastScriptTestID -= 1
    
    def reAddScriptTest(self, newSizer, scriptTest):
        """
        It adds a test script line to the panel sizer.
        @param newSizer: a new sizer to this panel.
        @param scriptTest: the test script line to be added.
        """
        newSizer.Add(scriptTest.emptySpace, (self.lastInsertedRow,0), wx.DefaultSpan, wx.ALIGN_LEFT)
        newSizer.Add(scriptTest.checkBox, (self.lastInsertedRow,1), (1,1), wx.EXPAND)
        newSizer.Add(scriptTest.textCtrl,(self.lastInsertedRow,2), (1,12), wx.EXPAND)
        newSizer.Add(scriptTest.browseButton, (self.lastInsertedRow,14), (1,1), wx.ALIGN_CENTER)
        newSizer.Add(scriptTest.removeButton, (self.lastInsertedRow,15), (1,1), wx.ALIGN_CENTER)
        self.incrementLastInsertedRow()
    
    def removeScriptTest(self, scriptTest):
        """
        It removes a test script line from the panel.
        @param scriptTest: the test script line to be removed. 
        """
        self.gridBagSizer.Remove(scriptTest.emptySpace)
        self.gridBagSizer.Remove(scriptTest.browseButton)
        self.gridBagSizer.Remove(scriptTest.checkBox)
        self.gridBagSizer.Remove(scriptTest.removeButton)
        self.gridBagSizer.Remove(scriptTest.textCtrl)
        self.decrementLastInsertedRow()
        self.decrementLastScriptTestID()
        
    def getTestScripts(self):
        """
        @return: all the test scripts selected by the user.
        """
        testScripts = []
        for scriptTest in self.idToScriptTest.values():
            testScript = scriptTest.textCtrl.GetValue()  
            if scriptTest.checkBox.IsChecked() and testScript != None and testScript != '':
                testScripts.append(testScript)
                
        return testScripts
    
    def getScriptsToSave(self):
        scriptsToSave = []
        for scriptTest in self.idToScriptTest.values():
            testScript = scriptTest.textCtrl.GetValue()  
            if testScript != None and testScript != '':
                scriptsToSave.append(ScriptToSave(testScript, scriptTest.checkBox.IsChecked()))
                
        return scriptsToSave
    
    def addTestScripts(self, testScripts):
        if len(self.getAllTestScripts()) == 0:
            self.removeAllTests()
        for testScript in testScripts:
            self.addScriptTest(testScript, True)
    
    def setTestScripts(self, testScripts):
        if len(testScripts) <= 0:
            return
        self.removeAllTests()
        for testScript in testScripts:
            self.addScriptTest(testScript.getFile(), testScript.isSelected())

        self.gridBagSizer.Layout()
        self.Layout()
        self.GetParent().Layout()
        
    def reset(self):
        self.removeAllTests()
        self.addEmptyScriptTest()
        self.gridBagSizer.Layout()
        self.Layout()
        self.GetParent().Layout()

            
    def removeAllTests(self):
        removed = []
        for test in self.idToScriptTest.values():
            self.removeScriptTest(test)
            removed.append(test)
            
        for i in range(len(removed)):
            removed[i].Destroy()
        self.idToScriptTest.clear()
        self.Layout()
        
        
    def getAllTestScripts(self):
        """
        @return: all the test scripts by the user, event if it is not selected.
        """        
        testScripts = []
        for scriptTest in self.idToScriptTest.values():
            testScript = scriptTest.textCtrl.GetValue()  
            if testScript != None and testScript != '':
                testScripts.append(testScript)
                
        return testScripts